// I believe it can be simplified. 

// Auxiliary Functions:

function findMatrixNode(node) {
	
	var parent;
	
	parent=node;
	
	while(parent!=null){
		if(parent.operator=="matrix") {
			return parent;
		}
		parent=parent.parent;
	}
	
	return null;
	
}


function findRowNode(node) {
	
	var parent;
	
	parent=node;
	
	while(parent!=null){
		if(parent.operator=="row") {
			return parent;
		}
		parent=parent.parent;
	}
	
	return null;
	
}

function findColumnNode(node) {
	
	var parent;
	
	parent=node;
	
	while(parent!=null){
		if(parent.operator=="column") {
			return parent;
		}
		parent=parent.parent;
	}
	
	return null;
	
}

// Core Functions:
function deleteColumn(node) { //delete now
	
	var parent=null;
	var column=null;
	var row=null;
	var position;
	var childrenNode;
	var tempCaret=null;
	
	column=findColumnNode(node);
	
	row=findRowNode(column);
	
	parent=findMatrixNode(row);
	
	position=row.children.indexOf(column);
	
	childrenNode=parent.children;
	length=childrenNode.length;
	
	for(var i=0;i<length;i++){
		childrenNode[i].children[position].remove();
	}
	
// move caret

	parent.columnLength--;

}

function deleteRow() { // delete now

	var parent=null;
	var row=null;
	var childrenNode=null;
	var length;
	
	row=findRowNode(node);
	
	parent=findMatrixNode(row);
	
	childrenNode=row.children;
	
	length=parent.columnLength;
	
	for(var i=0;i<length;i++){
		childrenNode[i].remove();   //all content will be removed.
	}
	
// move caret

	parent.rowLength--;

}



function addColumn(node) { // add after current column

	var parent=null;
	var column=null;
	var row=null;
	var position;
	var childrenNode;
	var tempCaret=null;
	
	parent=findMatrixNode(node);
	
	column=findColumnNode(node);
	
	row=findRowNode(column);
	
	position=row.children.indexOf(column);
	
	childrenNode=parent.children;
	length=childrenNode.length;
	
	for(var i=0;i<length;i++){
		tempCaret=subOperatorInsertAfter(childrenNode[i].children[position],"column");
		tempCaret=contentNodeAppend(tempCaret,1);
	}
	
	caret=parent.children[parent.rowLength-1].children[position+1].children[0];
	
	parent.columnLength++;
	
}

function addRow(node) { // add after current row 

	var parent=null;
	var row=null;
	var tempCaret=null;
	
	row=findRowNode(node);
	
	parent=findMatrixNode(row);
	
	row=subOperatorInsertBefore(row,"row");
	
	for(var i=0;i<parent.columnLength;i++){
		tempCaret=subOperatorAppend(row,"column");
		tempCaret=contentNodeAppend(tempCaret,1);
	}

	caret=row.children[0].children[0];
	
	parent.rowLength++;

}

// function clear

function matrix(node){

	caret=superOperatorInsert(caret,"matrix");
		
	caret.rowLength=1;
	caret.columnLength=1;
		
	caret=subOperatorAppend(caret,"row");
		
	caret=subOperatorAppend(caret,"column");
		
	caret=contentNodeAppend(caret,1); // 1 meaning the same level. 

}

function offSetForColumn(node) {
	
	node.upOffSet=upOffSetChildren(node);
	
	node.downOffSet=downOffSetChildren(node);
	
}

function offSetForMatrix(node) {
	
	var rowLength=node.rowLength;
	var columnLength=node.columnLength;
	// this node must be matrix node
	
	
	var tempMetric,temp;
	
	var metric=new Node();

// filling the metric matrix

	for(var i=0;i<rowLength;i++) {
		tempMetric=new Node();
		tempMetric.append(metric);
		for(var j=0;j<columnLength;j++)
			{
				temp=new Node();
				temp.append(tempMetric);
				temp.width=node.children[i].children[j].width;
				temp.upOffset=node.children[i].children[j].upOffSet+node.children[i].children[j].height;
				temp.downOffset=node.children[i].children[j].downOffSet;
			}
	}
	
	var columnMetric=new Array(columnLength);
	var rowMetric=new Array(rowLength);
	
	var destColumnMetric=new Array(columnLength);
	var destRowMetric=new Array(rowLength);
	
	var maxWidth;
	var maxUpOffset;
	var maxDownOffset;
	
// find maximum width for each column;

	for(var i=0;i<columnLength;i++) {
		maxWidth=0;
		for(var j=0;j<rowLength;j++)
			{
				maxWidth=Math.max(metric.children[j].children[i].width,maxWidth);
			}
		columnMetric[i]=maxWidth;
	}
	
	destColumnMetric[0]=columnMetric[0];
	
// processing width;

	for(var i=1;i<columnLength;i++)
	{
		destColumnMetric[i]=columnMetric[i]+destColumnMetric[i-1];
	}
	
	node.width=destColumnMetric[columnLength-1];


// find maximum height for each row;

	for(var i=0;i<rowLength;i++) {
		maxUpOffset=0;
		maxDownOffset=0;
		for(var j=0;j<columnLength;j++)
			{
				maxUpOffset=Math.max(metric.children[i].children[j].upOffset,maxUpOffset);
				maxDownOffset=Math.max(metric.children[i].children[j].downOffset,maxDownOffset);
			}
		rowMetric[i]={upOffset: maxUpOffset, 
					downOffset: maxDownOffset,
					height: maxUpOffset+maxDownOffset
					};
	}
	
	node.columnMetric=columnMetric;
	node.rowMetric=rowMetric;
	
// processing height;
	
	destRowMetric[0]=rowMetric[0].height;
	
	for(var i=1;i<rowLength;i++)
	{
		destRowMetric[i]=rowMetric[i].height+destRowMetric[i-1];
	}
	
	node.height=destRowMetric[rowLength-1];
	console.log(node.height);
	
// start to do real offset;

	// input 
	var thisWidth;
	var thisHeight=heightCaret(node);
	
	node.width+=thisHeight/2*(columnLength-1)+thisHeight/4;
//	node.height+=thisHeight/4*rowLength;
	 
	var totalLeft;
	
	// result
	var destLeft;
	var destBottom;

	for(var i=0;i<rowLength;i++) {
		totalLeft=0;
		for(var j=0;j<columnLength;j++)
			{
				thisWidth=metric.children[i].children[j].width;
				destLeft=-(columnMetric[j]+thisWidth)/2+destColumnMetric[j]+thisHeight/8+thisHeight/2*j;
				destBottom=-(node.height-thisHeight)/2-rowMetric[i].upOffset+destRowMetric[i];
				node.children[i].children[j].node.css('left',destLeft);
				node.children[i].children[j].node.css('bottom',destBottom);
			}
	}
	
	
	node.upOffSet=(node.height-thisHeight)/2;
	node.downOffSet=node.upOffSet;
	
	node.height=thisHeight; //restore the height definition
}